package org.geektimes.web.mvc;


import org.apache.commons.lang.StringUtils;
import org.geektimes.web.mvc.controller.Controller;
import org.geektimes.web.mvc.controller.PageController;
import org.geektimes.web.mvc.handler.HandlerMethodInfo;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

public class DispatchServlet extends GenericServlet {
    private Map<String, HandlerMethodInfo> handlerMethodInfoMapping=new HashMap<>();

    private Map<String, Controller> controllerMapping=new HashMap<>();

    @Override
    public void init()  {
        initHandlerMethod();
    }

    private void initHandlerMethod() {
        ServiceLoader<Controller> load = ServiceLoader.load(Controller.class);
        for(Controller controller:load){
            Class<? extends Controller> aClass = controller.getClass();
            Path annotation = aClass.getAnnotation(Path.class);
            String requestPath=annotation.value();
            Method[] methods = aClass.getDeclaredMethods();
            for(Method method:methods){
                requestPath+=method.getAnnotation(Path.class).value();
                Set<String> methodSupport = findMethodSupport(method);
                handlerMethodInfoMapping.put(requestPath,new HandlerMethodInfo(requestPath,method,methodSupport));
            }
            //requestPath->Controller
            controllerMapping.put(requestPath,controller);
        }
    }

    private Set<String> findMethodSupport (Method method) {

        Set<String> httpMethodSet=new HashSet<>();
        Annotation[] annotations = method.getAnnotations();
        for(Annotation annotation:annotations){
            //嵌套属性
            if (annotation.annotationType().getAnnotation(HttpMethod.class)!=null) {
                httpMethodSet.add(annotation.annotationType().getAnnotation(HttpMethod.class).value());
            }
        }

        if(httpMethodSet.isEmpty()){
            Collection<String> strings = Arrays.asList(HttpMethod.DELETE, HttpMethod.GET
                    , HttpMethod.HEAD, HttpMethod.OPTIONS
                    , HttpMethod.POST, HttpMethod.PUT);
            httpMethodSet.addAll(strings);
            Collections.unmodifiableSet(httpMethodSet);
        }
        return Collections.unmodifiableSet(httpMethodSet);
    }

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request=HttpServletRequest.class.cast(req);
        HttpServletResponse response=HttpServletResponse.class.cast(res);
        //uri 处理根目录  /user_web_war/hello/ 把user_web_war/处理调
        String requestURI = request.getRequestURI();
        // /user_web_war
        String contextPath=request.getContextPath();
        // 截取资源描述
        String prefixPath= StringUtils.substringAfter(requestURI
                ,contextPath.replace("//","/"));
        req.getServletContext().log(prefixPath);
        Controller controller = controllerMapping.get(prefixPath);
        if(controller!=null){
            if(controller instanceof PageController){
                HandlerMethodInfo handlerMethodInfo = handlerMethodInfoMapping.get(prefixPath);
                //未找到处理器
                if(Objects.isNull(handlerMethodInfo)){
                    response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                    return;
                }
                if(handlerMethodInfo.getSupportHttpMethods().contains(request.getMethod())){
                   PageController pageController=(PageController) controller;
                    String viewPath = pageController.execute(request, response);
//                    //静态页面转发 在当前资源目录下
//                    request.getRequestDispatcher(contextPath+execute).forward(request,response);
                    if(!viewPath.startsWith("/")){
                        viewPath="/"+viewPath;
                    }
                    ServletContext servletContext = request.getServletContext();
                    RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher(viewPath);
                    requestDispatcher.forward(request,response);
                }
            }

        }
    }


}
